package edu.sjtu.grid.workflow.facts;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.Element;

import edu.sjtu.grid.workflow.graph.Graph;
import edu.sjtu.grid.workflow.graph.Node;
import edu.sjtu.grid.workflow.iterator.UpwardRankIterator;

public class ADAG implements Graph {

	//private Facts facts = null;
	
	private String name = null;
	private int jobCount = 0;
	private int fileCount = 0;
	private int childCount = 0;
	
	private Job jobList[] = null;
	private Map<String, Job> idToJob = null;
	private List<Job> entryJobList = null;
	private List<Job> exitJobList = null;
	
	@SuppressWarnings("unchecked")
	public ADAG(Facts facts, Element eAdag)
	{	
        //init
		//this.facts = facts;
		this.name = eAdag.attributeValue("name");
		this.jobCount = Integer.parseInt(eAdag.attributeValue("jobCount"));
		this.fileCount = Integer.parseInt(eAdag.attributeValue("fileCount"));
		this.childCount = Integer.parseInt(eAdag.attributeValue("childCount"));
		
		this.jobList = new Job[this.jobCount];
		this.idToJob = new HashMap<String, Job>();
        
		//Job
		int index = 0;
        for (Iterator<Element> i = eAdag.elementIterator("job"); i.hasNext(); ) {
            Element eJob = (Element)i.next();
            Job job = new Job(facts, eJob, index);
            this.idToJob.put(job.getId(), job);
            this.jobList[index++] = job;
        }
        
        //child
        for (Iterator<Element> i = eAdag.elementIterator("child"); i.hasNext(); ) {
            Element eChild = (Element)i.next();
            String sChildRef = eChild.attributeValue("ref");
            Job childJob = idToJob.get(sChildRef);
            //parent
            for(Iterator<Element> j = eChild.elementIterator("parent"); j.hasNext(); ){
            	Element eParent = (Element)j.next();
            	String sParentRef = eParent.attributeValue("ref");
            	Job parentJob = idToJob.get(sParentRef);
            	childJob.addParent(parentJob);
            	parentJob.addChild(childJob);
            }
        }
        
        //engryJobList & exitJobList
        this.entryJobList = new ArrayList<Job>();
        this.exitJobList = new ArrayList<Job>();
        for(Job job : jobList)
		{
			if(job.getParentNumber() == 0)
				this.entryJobList.add(job);
			if(job.getChildNumber() == 0)
				this.exitJobList.add(job);
		}
	}
	public String getName() {
		return name;
	}
	public int getJobCount() {
		return jobCount;
	}
	public int getFileCount() {
		return fileCount;
	}
	public int getChildCount() {
		return childCount;
	}
	public Job[] getJobList() {
		return jobList;
	}
	public Map<String, Job> getIdToJob() {
		return idToJob;
	}
	public List<Job> getEntryJobList()
	{
		return this.entryJobList;
	}
	public List<Job> exitJobList()
	{
		return this.exitJobList;
	}
	
	public String toString()
	{
		StringBuilder s = new StringBuilder();
		
		//graph info
		s.append("----------adag----------\n");
		s.append("name=" + this.name + "\n");
		s.append("jobCount=" + this.jobCount + "\n");
		s.append("fileCount=" + this.fileCount + "\n");
		s.append("childCount=" + this.childCount + "\n");
		
		//job info
		s.append("\nindex\tid\t\tname\t\t\t\truntime\n");
		for(int i=0; i<this.jobCount; i++)
			s.append(this.jobList[i].toString());
		
		//uses
		s.append("\nindex\tid\t\tuses\n");
		for(int i=0; i<this.jobCount; i++)
			s.append(this.jobList[i].getUseString());
		
		//parent child
		s.append("\nparent-index\tparent-id\tchild-index\tchild-id\tdata-size\n");
		for(int i=0; i<this.jobCount; i++)
			s.append(this.jobList[i].getParentChildString());
		
		//child parent
		/*s.append("\nchild-index\tchild-id\tparent-index\tparent-id\tdata-size\n");
		for(int i=0; i<this.jobCount; i++)
			s.append(this.jobList[i].getChildParentString());*/
		
		return s.toString();
	}
	
	@Override
	public Node[] getNodeList() {
		return this.getJobList();
	}
	
	@Override
	public UpwardRankIterator getUpwardRankIterator()
	{
		return new UpwardRankIterator(this);
	}

}
